package com.adcc.ags.msgStore.service;

import com.adcc.ags.msgStore.common.Constant;
import com.adcc.ags.msgStore.dao.MsgStoreDao;
import com.adcc.ags.msgStore.dao.MsgStoreDaoImpl;
import com.adcc.ags.msgStore.entity.db.DBErrorCode;
import com.adcc.ags.msgStore.entity.db.DBInfo;
import com.adcc.ags.msgStore.entity.db.DBMessage;
import com.adcc.ags.msgStore.entity.db.DBState;
import com.adcc.utility.log.Log;
import com.adcc.utility.mq.entity.Message;
import com.adcc.utility.time.Time;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.common.base.Strings;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by ZHANG on 2017/3/1.
 */
public class MsgStoreInDBServiceImpl extends MsgStoreInDBService {


    private MsgStoreDao msgStoreDao = MsgStoreDaoImpl.getInstance();

    /**
     * 保存报文到oracle数据库中
     * @param message
     */
    @Override
    public DBErrorCode saveMessage(Optional<DBMessage> message) {
        if(message.isPresent()){
            return msgStoreDao.saveDBMessage(message.get());
        }else{
            return DBErrorCode.CONVERSION_ERROR;
        }
    }

    /**
     * 更新oracle数据库中的报文信息
     * @param message
     * @return
     */
    @Override
    public DBErrorCode updateMessage(Optional<DBMessage> message) {
        if(message.isPresent()){
            return msgStoreDao.updateDBMessage(message.get());
        }else{
            return DBErrorCode.CONVERSION_ERROR;
        }
    }

    /**
     * 保存或更新message
     * @param message
     * @return
     */
    @Override
    public DBErrorCode saveOrUpdateMessage(Message message) {
        Optional<DBMessage> dbMessage = changeMQMsgToDBMsg(message);
        String dealType = String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_FLAG));
        Map<String,Object> map=msgStoreDao.isExit(dbMessage.get().getMsgId());
        DBErrorCode errorCode = DBErrorCode.NO_ERROR;
        if(map.get(Constant.IS_EXIT_KEY)!=null){
            if((boolean)map.get(Constant.IS_EXIT_KEY) == true && Constant.TRAFFIC_MESSAGE_UPDATE.equals(dealType)){
                DBMessage dbMessageExit = msgStoreDao.findMsgById(dbMessage.get().getMsgId());
                if(dbMessageExit!=null && !Strings.isNullOrEmpty(dbMessageExit.getErrorUserId())){
                    dbMessage.get().setErrorUserId(dbMessageExit.getErrorUserId()+","+dbMessage.get().getErrorUserId());
                }
                errorCode = updateMessage(dbMessage);
            }else if((boolean)map.get(Constant.IS_EXIT_KEY) == false && Constant.TRAFFIC_MESSAGE_SAVE.equals(dealType)){
                errorCode = saveMessage(dbMessage);
                // 如果报文长度超过64KB，将报文存储到文件当中
//                if(message.getContent().length > Constant.TRAFFIC_MESSAGE_BIG_DATA_SIZE){
//                    MsgProxy.getInstance().getMsgStoreInFileActor().tell(message, MsgProxy.getInstance().getMsgStoreInFileActor());
//                    saveMessageToFile(message);
//                }
            }else{
                errorCode = DBErrorCode.MATCH_ERROR;
            }
        }else {
            errorCode = (DBErrorCode)map.get(Constant.ERROR_CODE_KEY);
        }
        return  errorCode;
    }

    /**
     * 将获取的MQ信息转换成DBMessage实体信息
     * @param message
     * @return
     */
    public Optional<DBMessage> changeMQMsgToDBMsg(Message message){
        try {
            String dealType = String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_FLAG));
            Map<String,String> map = null;
            DBMessage dbMessage = new DBMessage();
            dbMessage.setDatetime(new Date());
            //文件生成路径
            if(Constant.TRAFFIC_MESSAGE_SAVE.equals(dealType)){
                dbMessage.setMsgType(String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_TYPE)));
                String receiver = String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_RECEIVER));
                if(Strings.isNullOrEmpty(receiver) || Constant.TRAFFIC_MESSAGE_RECEIVER_NULL.equals(receiver)){
                    dbMessage.setReceiver("");
                }else{
                    dbMessage.setReceiver(receiver);
                }
                dbMessage.setSender(String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_SENDER)));
                dbMessage.setMsgId(String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_MSG_ID)));
                // 如果报文长度超过64KB，报文原文字段设置成报文的文件存储路径
                if(message.getContent().length > Constant.TRAFFIC_MESSAGE_BIG_DATA_SIZE){
                    Map<String,String> longMsgMap = new HashMap<>();
                    longMsgMap.put("smi","");
                    longMsgMap.put("fi","");
                    longMsgMap.put("an","");
                    longMsgMap.put("dspCode","");
                    longMsgMap.put("getTime", Time.getCurDateStr(Time.yyyy_MM_dd_HH_mm_ss));
                    try {
                        String json = new ObjectMapper().writeValueAsString(longMsgMap);
                        dbMessage.setRawMsg(json);
                    }catch (Exception e){
                        Log.error(getClass().getName(),"parse map to json error!",e);
                    }
                    dbMessage.setLongMsg(message.getContent());
                    dbMessage.setType(1);
                }else{
                    dbMessage.setType(0);
                    String rawMsg = message.toString();
                    String part1 = "";
                    String part2 = "";
                    String part3 = "";
                    String part4 = "";
                    String part5 = "";
                    if (rawMsg.length() > Constant.MESSAGE_SPLIT) {
                        switch ((rawMsg.length() / Constant.MESSAGE_SPLIT)) {
                            //If content's length between 4001 and 8000,split it to two parts.
                            case 1:
                                part1 = rawMsg.substring(Constant.MESSAGE_SPLIT);
                                break;
                            //If content's length between 8001 and 12000,split it to three parts.
                            case 2:
                                part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                                part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2);
                                break;
                            //If content's length between 12001 and 16000,split it to four parts.
                            case 3:
                                part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                                part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                                part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3);
                                break;
                            //If content's length between 16001 and 20000,split it to five parts.
                            case 4:
                                part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                                part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                                part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3, Constant.MESSAGE_SPLIT * 4);
                                part4 = rawMsg.substring(Constant.MESSAGE_SPLIT * 4);
                                break;
                            //If content's length between 20001 and 24000,split it to six parts.
                            case 5:
                                part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                                part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                                part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3, Constant.MESSAGE_SPLIT * 4);
                                part4 = rawMsg.substring(Constant.MESSAGE_SPLIT * 4, Constant.MESSAGE_SPLIT * 5);
                                part5 = rawMsg.substring(Constant.MESSAGE_SPLIT * 5);
                                break;
                            //If content's length is 24000,split it to six parts.
                            default:
                                part1 = rawMsg.substring(Constant.MESSAGE_SPLIT, Constant.MESSAGE_SPLIT * 2);
                                part2 = rawMsg.substring(Constant.MESSAGE_SPLIT * 2, Constant.MESSAGE_SPLIT * 3);
                                part3 = rawMsg.substring(Constant.MESSAGE_SPLIT * 3, Constant.MESSAGE_SPLIT * 4);
                                part4 = rawMsg.substring(Constant.MESSAGE_SPLIT * 4, Constant.MESSAGE_SPLIT * 5);
                                part5 = rawMsg.substring(Constant.MESSAGE_SPLIT * 5);
                                break;
                        }
                        //Put message content from 1 to 4000(if message content's length is less than 4000,end at the last character) into RawMsg.
                        dbMessage.setRawMsg(rawMsg.substring(0, Constant.MESSAGE_SPLIT));
                        dbMessage.setPart1(part1);
                        dbMessage.setPart2(part2);
                        dbMessage.setPart3(part3);
                        dbMessage.setPart4(part4);
                        dbMessage.setPart5(part5);
                    } else {
                        //If message content's length is less than 4000,put it all into RAWMSG of DB.
                        dbMessage.setRawMsg(rawMsg);
                    }
                    //If message content's length is bigger than 24000,give a message to remind length is more than max.
                    if (rawMsg.length() > Constant.MESSAGE_SPLIT * 6) {
                        part5 = part5.substring(Constant.MESSAGE_SPLIT * 5, (Constant.MESSAGE_SPLIT * 6 - 41));
                        part5 += "!!!message length is more than 24000!!!";
                        dbMessage.setPart5(part5);
                    }
                }
            }else if(Constant.TRAFFIC_MESSAGE_UPDATE.equals(dealType)){
                map = new ObjectMapper().readValue(message.toString(),HashMap.class);
                String receiver = map.get(Constant.TRAFFIC_MESSAGE_RECEIVER);
                if(Strings.isNullOrEmpty(receiver) || Constant.TRAFFIC_MESSAGE_RECEIVER_NULL.equals(receiver)){
                    dbMessage.setReceiver("");
                }else{
                    dbMessage.setReceiver(receiver);
                }
                dbMessage.setErrorCode(map.get(Constant.TRAFFIC_MESSAGE_ERROR_CODE));
                dbMessage.setMsgId(String.valueOf(message.getHead().get(Constant.TRAFFIC_MESSAGE_MSG_ID)));
                dbMessage.setErrorUserId(map.get(Constant.TRAFFIC_MESSAGE_ERROR_USER));
            }
            return Optional.of(dbMessage);
        } catch (IOException e) {
            Log.error(MsgStoreInDBServiceImpl.class.getName(), "changeMQMsgToDBMsg() error", e);
            return Optional.absent();
        }
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if(message == null){
            Log.error(MsgStoreInDBServiceImpl.class.getName(), "receive message is null");
            unhandled(message);
        }else{
            if(message instanceof Message){
                Message msg = (Message)message;
                DBErrorCode flag = saveOrUpdateMessage(msg);
                if (flag == DBErrorCode.CONNECT_ERROR) {
                    Log.error(MsgStoreInDBServiceImpl.class.getName(), "connect to database failed!");
                    DBInfo.getInstance().setState(DBState.CONNECTING);
                } else if(flag == DBErrorCode.SEND_ERROR) {
                    Log.error(MsgStoreInDBServiceImpl.class.getName(), "save message to oracle error!\r\n"+msg.toString());
                } else if(flag == DBErrorCode.UPDATE_ERROR) {
                    Log.error(MsgStoreInDBServiceImpl.class.getName(), "update message to oracle error!\r\n"+msg.toString());
                } else if(flag == DBErrorCode.MATCH_ERROR) {
                    Log.error(MsgStoreInDBServiceImpl.class.getName(), "Data that is saved or updated does not match the data in the database!\r\n"+msg.toString());
                }
            }
        }
    }
}
